convert ozi to Format class. (#1232)
authortsteven4 <13596209+tsteven4@users.noreply.github.com>
Sun, 19 Nov 2023 01:18:04 +0000 (18:18 -0700)
committerGitHub <noreply@github.com>
Sun, 19 Nov 2023 01:18:04 +0000 (18:18 -0700)
* convert ozi to Format class.

There is a subtle difference in the writer, the index is now
reset for every invocation.  This only matters if the writer is
used more than once. I believe this was the intent.

* fool with QIODevice and it's inheritence of QIODeviceBase.

CMakeLists.txt
ozi.cc
ozi.h [new file with mode: 0644]
vecs.cc

index 3308221d2ad5ba4d9994b3139e233d8ade0e5c2b..1c01b45d9a6e0b96a141d3f45cba9b4f3cb9477e 100644 (file)
@@ -233,6 +233,7 @@ set(HEADERS
   mkshort.h
   nmea.h
   osm.h
+  ozi.h
   qstarz_bl_1000.h
   random.h
   session.h
diff --git a/ozi.cc b/ozi.cc
index 74e33262a80e89d83a979594965600592a00e259..d1ab73aa998a964b581535ba864fa123227f0bc8 100644 (file)
--- a/ozi.cc
+++ b/ozi.cc
@@ -36,6 +36,8 @@
 
  */
 
+#include "ozi.h"
+
 #include <cctype>                 // for tolower
 #include <cmath>                  // for lround
 
 #include <QChar>                  // for operator==, QChar
 #include <QFile>                  // for QFile
 #include <QFileInfo>              // for QFileInfo
-#include <QIODevice>              // for operator|, QIODevice::WriteOnly, QIODevice::ReadOnly, QIODevice, QIODevice::OpenModeFlag
-#include <QString>                // for QString
+#include <QFlags>                 // for QFlags
+#include <QIODevice>              // for operator&, QIODevice
+#include <QList>                  // for QList, QList<>::const_iterator
+#include <QString>                // for QString, operator==
 #include <QStringList>            // for QStringList
+#include <QStringLiteral>         // for qMakeStringPrivate, QStringLiteral
 #include <QTextStream>            // for QTextStream, operator<<, qSetRealNumberPrecision, QTextStream::FixedNotation
-#include <QVector>                // for QVector
 #include <Qt>                     // for CaseInsensitive
 #include <QtGlobal>               // for qPrintable
 
 #include "defs.h"
 #include "csv_util.h"             // for csv_stringclean
-#include "formspec.h"             // for FsChainAdd, FsChainFind, kFsOzi, FormatSpecificData
-#include "jeeps/gpsmath.h"        // for GPS_Math_Known_Datum_To_WGS84_M
+#include "formspec.h"             // for FormatSpecificDataList, kFsOzi
+#include "jeeps/gpsmath.h"        // for GPS_Lookup_Datum_Index, GPS_Math_Known_Datum_To_WGS84_M
 #include "mkshort.h"              // for MakeShort
 #include "src/core/datetime.h"    // for DateTime
 #include "src/core/textstream.h"  // for TextStream
 #define BADCHARS       ",\r\n"
 #define DAYS_SINCE_1990        25569
 
-struct ozi_fsdata : FormatSpecificData {
-  ozi_fsdata() : FormatSpecificData(kFsOzi) {}
-
-  ozi_fsdata* clone() const override
-  {
-    return new ozi_fsdata(*this);
-  }
-
-  int fgcolor{0};
-  int bgcolor{65535};
-};
-
-static gpsbabel::TextStream* stream = nullptr;
-
-static MakeShort* mkshort_handle;
-static route_head* trk_head;
-static route_head* rte_head;
-
-static int track_out_count;
-static int route_out_count;
-static int route_wpt_count;
-static int new_track;
-
-static char* snlenopt = nullptr;
-static char* snwhiteopt = nullptr;
-static char* snupperopt = nullptr;
-static char* snuniqueopt = nullptr;
-static char* wptfgcolor = nullptr;
-static char* wptbgcolor = nullptr;
-static char* pack_opt = nullptr;
-static int datum;
-static char* proximityarg = nullptr;
-static double proximity;
-static char* altunit_opt;
-static char* proxunit_opt;
-static char altunit;
-static char proxunit;
-static double alt_scale;
-static double prox_scale;
-static char* opt_codec;
-
-static
-QVector<arglist_t> ozi_args = {
-  {
-    "pack", &pack_opt, "Write all tracks into one file",
-    nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
-  },
-  {
-    "snlen", &snlenopt, "Max synthesized shortname length",
-    "32", ARGTYPE_INT, "1", nullptr, nullptr
-  },
-  {
-    "snwhite", &snwhiteopt, "Allow whitespace synth. shortnames",
-    nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
-  },
-  {
-    "snupper", &snupperopt, "UPPERCASE synth. shortnames",
-    nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
-  },
-  {
-    "snunique", &snuniqueopt, "Make synth. shortnames unique",
-    nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
-  },
-  {
-    "wptfgcolor", &wptfgcolor, "Waypoint foreground color",
-    "black", ARGTYPE_STRING, ARG_NOMINMAX, nullptr
-  },
-  {
-    "wptbgcolor", &wptbgcolor, "Waypoint background color",
-    "yellow", ARGTYPE_STRING, ARG_NOMINMAX, nullptr
-  },
-  {
-    "proximity", &proximityarg, "Proximity distance",
-    "0", ARGTYPE_STRING, ARG_NOMINMAX, nullptr
-  },
-  {
-    "altunit", &altunit_opt, "Unit used in altitude values",
-    "feet", ARGTYPE_STRING, ARG_NOMINMAX, nullptr
-  },
-  {
-    "proxunit", &proxunit_opt, "Unit used in proximity values",
-    "miles", ARGTYPE_STRING, ARG_NOMINMAX, nullptr
-  },
-  {
-    "codec", &opt_codec, "codec to use for reading and writing strings (default windows-1252)",
-    "windows-1252", ARGTYPE_STRING, ARG_NOMINMAX, nullptr
-  },
-};
-
-static gpsdata_type ozi_objective;
-
-static QString ozi_ofname;
-
-static void
-ozi_open_io(const QString& fname, QIODevice::OpenModeFlag mode)
+void
+OziFormat::ozi_open_io(const QString& fname, QIODevice::OpenModeFlag mode)
 {
   stream = new gpsbabel::TextStream;
   stream->open(fname, mode, MYNAME, opt_codec);
@@ -168,8 +79,8 @@ ozi_open_io(const QString& fname, QIODevice::OpenModeFlag mode)
   }
 }
 
-static void
-ozi_close_io()
+void
+OziFormat::ozi_close_io()
 {
   if (!stream) {
     return;
@@ -179,9 +90,8 @@ ozi_close_io()
   stream = nullptr;
 }
 
-static
-ozi_fsdata*
-ozi_alloc_fsdata()
+OziFormat::ozi_fsdata*
+OziFormat::ozi_alloc_fsdata()
 {
   auto* fsdata = new ozi_fsdata;
 
@@ -192,8 +102,8 @@ ozi_alloc_fsdata()
   return fsdata;
 }
 
-static QString
-ozi_get_time_str(const Waypoint* waypointp)
+QString
+OziFormat::ozi_get_time_str(const Waypoint* waypointp)
 {
   if (waypointp->creation_time.isValid()) {
     double time = (waypt_time(waypointp) / SECONDS_PER_DAY) + DAYS_SINCE_1990;
@@ -202,8 +112,8 @@ ozi_get_time_str(const Waypoint* waypointp)
   return QString("");
 }
 
-static void
-ozi_set_time_str(const QString& str, Waypoint* waypointp)
+void
+OziFormat::ozi_set_time_str(const QString& str, Waypoint* waypointp)
 {
   double ozi_time = str.toDouble();
 
@@ -213,8 +123,8 @@ ozi_set_time_str(const QString& str, Waypoint* waypointp)
   }
 }
 
-static void
-ozi_convert_datum(Waypoint* wpt)
+void
+OziFormat::ozi_convert_datum(Waypoint* wpt) const
 {
   if (datum != kDautmWGS84) {
     double lat, lon, alt;
@@ -225,8 +135,8 @@ ozi_convert_datum(Waypoint* wpt)
   }
 }
 
-static void
-ozi_openfile(const QString& fname)
+void
+OziFormat::ozi_openfile(const QString& fname)
 {
   const char* ozi_extensions[] = {nullptr, "plt", "wpt", "rte"};
 
@@ -266,8 +176,8 @@ ozi_openfile(const QString& fname)
   ozi_open_io(tmpname, QFile::WriteOnly);
 }
 
-static void
-ozi_track_hdr(const route_head* rte)
+void
+OziFormat::ozi_track_hdr(const route_head* rte)
 {
   if ((! pack_opt) || (track_out_count == 0)) {
     ozi_openfile(ozi_ofname);
@@ -285,8 +195,8 @@ ozi_track_hdr(const route_head* rte)
   new_track = 1;
 }
 
-static void
-ozi_track_disp(const Waypoint* waypointp)
+void
+OziFormat::ozi_track_disp(const Waypoint* waypointp)
 {
   double alt;
 
@@ -307,14 +217,20 @@ ozi_track_disp(const Waypoint* waypointp)
   new_track = 0;
 }
 
-static void
-ozi_track_pr()
+void
+OziFormat::ozi_track_pr()
 {
-  track_disp_all(ozi_track_hdr, nullptr, ozi_track_disp);
+  auto ozi_track_hdr_lambda = [this](const route_head* rte)->void {
+    ozi_track_hdr(rte);
+  };
+  auto ozi_track_disp_lambda = [this](const Waypoint* waypointp)->void {
+    ozi_track_disp(waypointp);
+  };
+  track_disp_all(ozi_track_hdr_lambda, nullptr, ozi_track_disp_lambda);
 }
 
-static void
-ozi_route_hdr(const route_head* rte)
+void
+OziFormat::ozi_route_hdr(const route_head* rte)
 {
   /* prologue on 1st pass only */
   if (route_out_count == 0) {
@@ -344,8 +260,8 @@ ozi_route_hdr(const route_head* rte)
                    << rte->rte_desc << ",\r\n";
 }
 
-static void
-ozi_route_disp(const Waypoint* waypointp)
+void
+OziFormat::ozi_route_disp(const Waypoint* waypointp)
 {
   route_wpt_count++;
 
@@ -390,14 +306,20 @@ ozi_route_disp(const Waypoint* waypointp)
 
 }
 
-static void
-ozi_route_pr()
+void
+OziFormat::ozi_route_pr()
 {
-  route_disp_all(ozi_route_hdr, nullptr, ozi_route_disp);
+  auto ozi_route_hdr_lambda = [this](const route_head* rte)->void {
+    ozi_route_hdr(rte);
+  };
+  auto ozi_route_disp_lambda = [this](const Waypoint* waypointp)->void {
+    ozi_route_disp(waypointp);
+  };
+  route_disp_all(ozi_route_hdr_lambda, nullptr, ozi_route_disp_lambda);
 }
 
-static void
-ozi_init_units(const int direction)    /* 0 = in; 1 = out */
+void
+OziFormat::ozi_init_units(const int direction) /* 0 = in; 1 = out */
 {
   altunit = tolower(*altunit_opt);
   switch (altunit) {
@@ -433,22 +355,22 @@ ozi_init_units(const int direction)       /* 0 = in; 1 = out */
   }
 }
 
-static void
-rd_init(const QString& fname)
+void
+OziFormat::rd_init(const QString& fname)
 {
   ozi_open_io(fname, QFile::ReadOnly);
 
   ozi_init_units(0);
 }
 
-static void
-rd_deinit()
+void
+OziFormat::rd_deinit()
 {
   ozi_close_io();
 }
 
-static void
-wr_init(const QString& fname)
+void
+OziFormat::wr_init(const QString& fname)
 {
 
   /* At this point, we have no idea whether we'll be writing waypoint,
@@ -484,8 +406,8 @@ wr_init(const QString& fname)
   parse_distance(proximityarg, &proximity, 1 / prox_scale, MYNAME);
 }
 
-static void
-wr_deinit()
+void
+OziFormat::wr_deinit()
 {
   ozi_close_io();
   ozi_ofname.clear();
@@ -494,8 +416,8 @@ wr_deinit()
   mkshort_handle = nullptr;
 }
 
-static void
-ozi_parse_waypt(int field, const QString& str, Waypoint* wpt_tmp, ozi_fsdata* fsdata)
+void
+OziFormat::ozi_parse_waypt(int field, const QString& str, Waypoint* wpt_tmp, ozi_fsdata* fsdata) const
 {
   double alt;
 
@@ -589,8 +511,8 @@ ozi_parse_waypt(int field, const QString& str, Waypoint* wpt_tmp, ozi_fsdata* fs
   }
 }
 
-static void
-ozi_parse_track(int field, const QString& str, Waypoint* wpt_tmp, char* trk_name)
+void
+OziFormat::ozi_parse_track(int field, const QString& str, Waypoint* wpt_tmp, char* trk_name)
 {
   if (str.isEmpty()) {
     return;
@@ -634,8 +556,8 @@ ozi_parse_track(int field, const QString& str, Waypoint* wpt_tmp, char* trk_name
   }
 }
 
-static void
-ozi_parse_routepoint(int field, const QString& str, Waypoint* wpt_tmp)
+void
+OziFormat::ozi_parse_routepoint(int field, const QString& str, Waypoint* wpt_tmp)
 {
   if (str.isEmpty()) {
     return;
@@ -694,8 +616,8 @@ ozi_parse_routepoint(int field, const QString& str, Waypoint* wpt_tmp)
   }
 }
 
-static void
-ozi_parse_routeheader(int field, const QString& str)
+void
+OziFormat::ozi_parse_routeheader(int field, const QString& str)
 {
 
   switch (field) {
@@ -724,8 +646,8 @@ ozi_parse_routeheader(int field, const QString& str)
   }
 }
 
-static void
-data_read()
+void
+OziFormat::read()
 {
   QString buff;
   char* trk_name = nullptr;
@@ -853,10 +775,9 @@ data_read()
   }
 }
 
-static void
-ozi_waypt_pr(const Waypoint* wpt)
+void
+OziFormat::ozi_waypt_pr(const Waypoint* wpt, int index)
 {
-  static int index = 0;
   double alt;
   QString description;
   QString shortname;
@@ -901,8 +822,6 @@ ozi_waypt_pr(const Waypoint* wpt)
     description = csv_stringclean(wpt->description, BADCHARS);
   }
 
-  index++;
-
   if (wpt->icon_descr.toInt()) {
     icon = wpt->icon_descr.toInt();
   }
@@ -931,8 +850,8 @@ ozi_waypt_pr(const Waypoint* wpt)
   }
 }
 
-static void
-data_write()
+void
+OziFormat::write()
 {
   if (waypt_count()) {
     track_out_count = route_out_count = 0;
@@ -942,7 +861,12 @@ data_write()
                      << "WGS 84\r\n"
                      << "Reserved 2\r\n"
                      << "Reserved 3\r\n";
-    waypt_disp_all(ozi_waypt_pr);
+
+    int index = 0;
+    auto ozi_waypt_pr_lambda = [this, &index](const Waypoint* waypointp)->void {
+      ozi_waypt_pr(waypointp, ++index);
+    };
+    waypt_disp_all(ozi_waypt_pr_lambda);
   }
 
   if (track_count()) {
@@ -957,17 +881,3 @@ data_write()
   }
 
 }
-
-ff_vecs_t ozi_vecs = {
-  ff_type_file,
-  FF_CAP_RW_ALL,
-  rd_init,
-  wr_init,
-  rd_deinit,
-  wr_deinit,
-  data_read,
-  data_write,
-  nullptr,
-  &ozi_args,
-  NULL_POS_OPS
-};
diff --git a/ozi.h b/ozi.h
new file mode 100644 (file)
index 0000000..bcb8a40
--- /dev/null
+++ b/ozi.h
@@ -0,0 +1,198 @@
+/*
+    OziExplorer Waypoints/Tracks/Routes
+    Comma Delimited
+
+    As described in OziExplorer Help File
+
+    Copyright (C) 2002-2005 Robert Lipe, robertlipe+source@gpsbabel.org
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+    Reference:
+    https://www.oziexplorer4.com/eng/help/fileformats.html
+
+    According to the OZI Explorer developer:
+    "There is no specified character set, it defaults to whatever 8 bit
+     character set "Windows" defaults to - normally CP-1252 but can vary
+     depending on Windows regional settings."
+
+    According to the reference, for some text fields:
+    "comma's not allowed in text fields, character 209 can be used instead
+     and a comma will be substituted."
+    This could work for windows-1252, but not for utf-8.
+    We don't support any special handling for character 209.
+
+ */
+#ifndef OZI_H_INCLUDED_
+#define OZI_H_INCLUDED_
+
+#include <QIODevice>              // for QIODeviceBase, QIODeviceBase::OpenModeFlag
+#include <QString>                // for QString
+#include <QVector>                // for QVector
+
+#include "defs.h"
+#include "format.h"               // for Format
+#include "formspec.h"             // for FormatSpecificData, kFsOzi
+#include "mkshort.h"              // for MakeShort
+#include "src/core/textstream.h"  // for TextStream
+
+
+class OziFormat : public Format
+{
+public:
+  QVector<arglist_t>* get_args() override
+  {
+    return &ozi_args;
+  }
+
+  ff_type get_type() const override
+  {
+    return ff_type_file;
+  }
+
+  QVector<ff_cap> get_cap() const override
+  {
+    return FF_CAP_RW_ALL;
+  }
+
+  void rd_init(const QString& fname) override;
+  void read() override;
+  void rd_deinit() override;
+  void wr_init(const QString& fname) override;
+  void write() override;
+  void wr_deinit() override;
+
+private:
+  /* Types */
+
+  struct ozi_fsdata : FormatSpecificData {
+    ozi_fsdata() : FormatSpecificData(kFsOzi) {}
+
+    ozi_fsdata* clone() const override
+    {
+      return new ozi_fsdata(*this);
+    }
+
+    int fgcolor{0};
+    int bgcolor{65535};
+  };
+
+  /* Member Functions */
+
+  void ozi_open_io(const QString& fname, QIODevice::OpenModeFlag mode);
+  void ozi_close_io();
+  ozi_fsdata* ozi_alloc_fsdata();
+  static QString ozi_get_time_str(const Waypoint* waypointp);
+  static void ozi_set_time_str(const QString& str, Waypoint* waypointp);
+  void ozi_convert_datum(Waypoint* wpt) const;
+  void ozi_openfile(const QString& fname);
+  void ozi_track_hdr(const route_head* rte);
+  void ozi_track_disp(const Waypoint* waypointp);
+  void ozi_track_pr();
+  void ozi_route_hdr(const route_head* rte);
+  void ozi_route_disp(const Waypoint* waypointp);
+  void ozi_route_pr();
+  void ozi_init_units(int direction);
+  void ozi_parse_waypt(int field, const QString& str, Waypoint* wpt_tmp, ozi_fsdata* fsdata) const;
+  void ozi_parse_track(int field, const QString& str, Waypoint* wpt_tmp, char* trk_name);
+  static void ozi_parse_routepoint(int field, const QString& str, Waypoint* wpt_tmp);
+  void ozi_parse_routeheader(int field, const QString& str);
+  void data_read();
+  void ozi_waypt_pr(const Waypoint* wpt, int index);
+  void data_write();
+
+  /* Data Members */
+
+  gpsbabel::TextStream* stream = nullptr;
+
+  MakeShort* mkshort_handle{};
+  route_head* trk_head{};
+  route_head* rte_head{};
+
+  int track_out_count{};
+  int route_out_count{};
+  int route_wpt_count{};
+  int new_track{};
+
+  char* snlenopt = nullptr;
+  char* snwhiteopt = nullptr;
+  char* snupperopt = nullptr;
+  char* snuniqueopt = nullptr;
+  char* wptfgcolor = nullptr;
+  char* wptbgcolor = nullptr;
+  char* pack_opt = nullptr;
+  int datum{};
+  char* proximityarg = nullptr;
+  double proximity{};
+  char* altunit_opt{};
+  char* proxunit_opt{};
+  char altunit{};
+  char proxunit{};
+  double alt_scale{};
+  double prox_scale{};
+  char* opt_codec{};
+
+  QVector<arglist_t> ozi_args = {
+    {
+      "pack", &pack_opt, "Write all tracks into one file",
+      nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+    },
+    {
+      "snlen", &snlenopt, "Max synthesized shortname length",
+      "32", ARGTYPE_INT, "1", nullptr, nullptr
+    },
+    {
+      "snwhite", &snwhiteopt, "Allow whitespace synth. shortnames",
+      nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+    },
+    {
+      "snupper", &snupperopt, "UPPERCASE synth. shortnames",
+      nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+    },
+    {
+      "snunique", &snuniqueopt, "Make synth. shortnames unique",
+      nullptr, ARGTYPE_BOOL, ARG_NOMINMAX, nullptr
+    },
+    {
+      "wptfgcolor", &wptfgcolor, "Waypoint foreground color",
+      "black", ARGTYPE_STRING, ARG_NOMINMAX, nullptr
+    },
+    {
+      "wptbgcolor", &wptbgcolor, "Waypoint background color",
+      "yellow", ARGTYPE_STRING, ARG_NOMINMAX, nullptr
+    },
+    {
+      "proximity", &proximityarg, "Proximity distance",
+      "0", ARGTYPE_STRING, ARG_NOMINMAX, nullptr
+    },
+    {
+      "altunit", &altunit_opt, "Unit used in altitude values",
+      "feet", ARGTYPE_STRING, ARG_NOMINMAX, nullptr
+    },
+    {
+      "proxunit", &proxunit_opt, "Unit used in proximity values",
+      "miles", ARGTYPE_STRING, ARG_NOMINMAX, nullptr
+    },
+    {
+      "codec", &opt_codec, "codec to use for reading and writing strings (default windows-1252)",
+      "windows-1252", ARGTYPE_STRING, ARG_NOMINMAX, nullptr
+    },
+  };
+
+  gpsdata_type ozi_objective{unknown_gpsdata};
+
+  QString ozi_ofname;
+};
+#endif // OZI_H_INCLUDED_
diff --git a/vecs.cc b/vecs.cc
index 0db4b44adcaf5e540821941e6dd731a45792c093..eb198a7f56c0a017998b79d742d2abece66c333f 100644 (file)
--- a/vecs.cc
+++ b/vecs.cc
@@ -65,6 +65,7 @@
 #include "lowranceusr.h"       // for LowranceusrFormat
 #include "nmea.h"              // for NmeaFormat
 #include "osm.h"               // for OsmFormat
+#include "ozi.h"               // for OziFormat
 #include "qstarz_bl_1000.h"    // for QstarzBL1000Format
 #include "random.h"            // for RandomFormat
 #include "shape.h"             // for ShapeFormat
@@ -82,7 +83,6 @@
 
 
 extern ff_vecs_t geo_vecs;
-extern ff_vecs_t ozi_vecs;
 #if MAXIMAL_ENABLED
 extern ff_vecs_t mtk_vecs;
 extern ff_vecs_t mtk_fvecs;
@@ -111,7 +111,7 @@ struct Vecs::Impl {
   GarminFormat garmin_fmt;
   GdbFormat gdb_fmt;
   NmeaFormat nmea_fmt;
-  LegacyFormat ozi_fmt {ozi_vecs};
+  OziFormat ozi_fmt;
   KmlFormat kml_fmt;
 #if MAXIMAL_ENABLED
   LowranceusrFormat lowranceusr_fmt;